/*
 * GPS_Region.c
 *
 *  Created on: 2015-9-29
 *      Author: WFL
 *
 *  Functions are wrote for GPSDataHandler Task
 */

#include "GPS_Region.h"
#include "GPS_Location_Handle.h"
#include "XFlash.h"
#include "CirGpsCommand.h"
#include "GPS_SatelliteData.h"
#include "GPS_PRE_NXT_ST.h"
#include "GPS_MMITransmitdata.h"

extern volatile MY_INFO MyInfo;
extern DATA_BASE_INFO DataBase;


#ifdef __cplusplus
#pragma DATA_SECTION("UserDataFile")
#else
#pragma DATA_SECTION(NearByRoad,"UserDataFile");
#endif
ST_DIST NearByRoad[MAX_INQURITY_ROAD];//MAX_INQURITY_ROAD=7


//Search Region Database
//Sending a command when enter a Region
#pragma CODE_SECTION(SearchRegionDatabase, "FuncsMap2H0SARam")
void SearchRegionDatabase(void)
{
	Uns i;
	REGION_INFO region_buf;
	volatile LgUns offset;

	offset=MyInfo.DBRegionOffset;
	if(CurrGpsInfo.State!='A')
		return;

	for(i=0;i<DataBase.RegCnt;i++)
	{
		//read region database
		S29G_FlashRead(&region_buf.Rsvd,offset,32);
		GPS_ConvertLonLat(&region_buf.Lon0_1,16,&region_buf.Longi,&region_buf.Lati);
		if(InAreaCheck(
						CurrGpsInfo.Longi,CurrGpsInfo.Lati,
						region_buf.Longi,region_buf.Lati,
						region_buf.L_Rht_lon,region_buf.L_Rht_lat,		//lower right
						region_buf.L_Rht_lon,region_buf.U_Lft_lat,		//upper right
						region_buf.U_Lft_lon,region_buf.U_Lft_lat,		//upper left
						region_buf.U_Lft_lon,region_buf.L_Rht_lat))		//lower left
		{
			EnterRegionHandler(i+1,&region_buf);
			return;
		}
		offset+=32;
	}
	if(MyInfo.CurrRegionIndex)
	{
		ToMMIData(Tx_Cmd_GPS_ExitRegion);
	}
	MyInfo.CurrRegionIndex=0;
	return;
}

//things to do when entering a new Region for the first time
#pragma CODE_SECTION(EnterRegionHandler, "FuncsMap2H0SARam")
void EnterRegionHandler(Uns index,REGION_INFO* region_buf)
{
	Uns i;
	LgUns lastST;
	LgUns invalidST[7];

	if(MyInfo.CurrRegionIndex==index)
		return;//still in the same Region, doing nothing.

	//renew current Region index
	MyInfo.CurrRegionIndex=index;

	//check invalid back station
	lastST = PRE_NXT_ST_Info[PREV_ST_1].ST_Index;
	invalidST[0] = region_buf->InvalidSTIndex[0]+((LgUns)region_buf->InvalidSTIndex[1]<<16);
	invalidST[1] = region_buf->InvalidSTIndex[2]+((LgUns)region_buf->InvalidSTIndex[3]<<16);
	invalidST[2] = region_buf->InvalidSTIndex[4]+((LgUns)region_buf->InvalidSTIndex[5]<<16);
	invalidST[3] = region_buf->InvalidSTIndex[6]+((LgUns)region_buf->InvalidSTIndex[7]<<16);
	invalidST[4] = region_buf->InvalidSTIndex[8]+((LgUns)region_buf->InvalidSTIndex[9]<<16);
	invalidST[5] = region_buf->InvalidSTIndex[10]+((LgUns)region_buf->InvalidSTIndex[11]<<16);
	invalidST[6] = region_buf->InvalidSTIndex[12]+((LgUns)region_buf->InvalidSTIndex[13]<<16);
	if(lastST != 0)
	{
		for(i=0;i<7;i++)
		{
			if(invalidST[i]==lastST)
				return;
		}
	}

	//handle for force Locked state
	if (MyInfo.MMI_SelAbs==2&&MyInfo.RoadLocked)
	{
		for(i=0;i<8;i++)
		{
			if(region_buf->Rd_Index[i]==MyInfo.LockedRoadIndex)
				return;
		}
	}

	//prepare 485 data
	//write to MMIData[MMI_BUF_MASK + 1]
	ToMMIData_Region((REGION_INFO *)region_buf);
}

//called by GPSDataHandler Task when receive command 0x4f
#pragma CODE_SECTION(LineAskingCmdHandler, "FuncsMap2H0SARam")
void LineAskingCmdHandler(void)
{
	Uns i;
	REGION_INFO region_buf;
	volatile LgUns offset;
	Uns roadindex[MAX_INQURITY_ROAD],roadcount;

	if(MyInfo.CurrRegionIndex)
	{
		offset=MyInfo.DBRegionOffset+MyInfo.CurrRegionIndex*32-32;
		S29G_FlashRead(&region_buf.Rsvd,offset,32);
		ToMMIData_Region((REGION_INFO *)&region_buf);
	}
	else
	{
		roadcount=InquiryNearbyRoad(roadindex);
		if(MyInfo.RoadLocked)
		{
			for(i=0;i<MAX_INQURITY_ROAD;i++)
			{
				if(roadindex[i]==MyInfo.LockedRoadIndex)
					break;
			}
			if(i==MAX_INQURITY_ROAD)
			{
				AddArrayHead(MyInfo.LockedRoadIndex,roadindex,MAX_INQURITY_ROAD);
				roadcount++;
				if(roadcount>7)
					roadcount=7;
			}
		}
		ToMMI_RoadSelection(Tx_Cmd_GPS_MultiRoad,roadindex,roadcount);
	}

}

#pragma CODE_SECTION(AddArrayHead, "FuncsMap2H0SARam")
void AddArrayHead(Uns headvalue,Uns* arr,Uns arrlen)
{
	Uns i;
	for(i=0;i<arrlen-1;i++)
	{
		arr[arrlen-1-i]=arr[arrlen-1-i-1];
	}
	arr[0]=headvalue;
}

//inquiry 7 nearby line,
#pragma CODE_SECTION(InquiryNearbyRoad, "FuncsMap2H0SARam")
Uns InquiryNearbyRoad(Uns* roadindex)
{
	Uns j,roadcount=0;
	LgUns i,dist=0,samecheck;
	ST_INFO temp;
	volatile LgUns offset;

	offset = MyInfo.DBStationOffset;
	for(i=0;i<DataBase.StCnt;i++)
	{
		S29G_FlashRead(&temp.RD_Index,offset,32);
		GPS_ConvertLonLat(&temp.Lon0_1,16,&temp.Longi,&temp.Lati);
		dist=GPS_GetDistance(CurrGpsInfo.Longi,CurrGpsInfo.Lati,temp.Longi,temp.Lati);
		if(dist<MAX_DIST/4)//5 kilometer
		{
			samecheck=0;
			for(j=0;j<roadcount;j++)
			{
				if(temp.RD_Index==NearByRoad[j].Index)
				{
					samecheck=1;
					if(dist<NearByRoad[j].Dist)
					{
						NearByRoad[j].Dist=dist;
					}
					break;
				}
			}
			if(!samecheck)
			{
				if(roadcount<MAX_INQURITY_ROAD)
				{
					NearByRoad[roadcount].Index=temp.RD_Index;
					NearByRoad[roadcount].Dist=dist;
					QuickSort_ST_DIST( (ST_DIST *) NearByRoad,0,roadcount);
					roadcount++;
				}
				else
				{
					if(dist<NearByRoad[MAX_INQURITY_ROAD-1].Dist)
					{
						NearByRoad[MAX_INQURITY_ROAD-1].Dist=dist;
						NearByRoad[MAX_INQURITY_ROAD-1].Index=temp.RD_Index;
						QuickSort_ST_DIST((ST_DIST*)NearByRoad,0,MAX_INQURITY_ROAD-1);
					}
				}
			}
		}
		offset+=32;
	}

	for(i=0;i<MAX_INQURITY_ROAD;i++)
	{
		roadindex[i]=NearByRoad[i].Index;
	}

	return roadcount;
}


///////////////////////////////////////////////////////////////////////////
//										END
///////////////////////////////////////////////////////////////////////////
